Repository navigation
fix(apply): refuse an unknown --build-id before tofu apply - #808
Merged
Merged
Conversation
`fluid apply --mode amend-and-build --build-id <id>` (and replace-and-build) checked the id only in the build runner, which keeps the builds whose id equals it and, with none left, logs "Build not found" and returns 1. On the OpenTofu engine the runner starts after `tofu apply`, so a mistyped id provisioned the product and then failed with a log line and exit 1. apply now runs the runner's match in a build mode, right after the build-id grammar gate, ahead of the apply hooks, tofu and the runner, on both engines. The refusal is a typed CLIError, apply_build_id_not_found, that names the id, lists the contract's build ids and says nothing was applied. Ids match exactly, as in the runner. An empty --build-id and a contract without builds are not checked, as before. The runner keeps its own check as the backstop. The Command Center run now reports apply_build_id_not_found, where it reported build_not_found:<id> after the infrastructure was applied.
5 of 9 tasks
This was referenced Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
fluid apply <contract> --mode amend-and-build --build-id <id>(andreplace-and-build) checked the id only in the build runner. The runner keeps the builds whose id equals--build-idand, with none left, logsBuild not foundand returns 1. On the OpenTofu engine (AWS, GCP, Snowflake, Confluent, Databricks and IaC plugin clouds) the runner starts after the apply hooks andtofu apply. So a mistyped--build-idprovisioned the product first and then failed with a log line.This PR runs the runner's own match at the start of the apply, right after the build-id grammar gate from #803. It runs in the build modes only, before the apply hooks,
tofuand the runner, on both engines:cli/apply.py::_gate_selected_build_for_applyrefuses a--build-idthat matches nobuilds[].idwithCLIErrorapply_build_id_not_found(ERR_APPLY_BUILD_ID_NOT_FOUND). The error shows the id (asrepr, so a stray space shows), the contract's build ids, a hint that ends "Nothing was applied", and catalog suggestions.--build-idand a contract without builds are not checked, because the runner does not refuse them either. A build with noidmatches nothing, as in the runner, and the hint says so.fluid apply.apply_build_id_not_found, where it reportedbuild_not_found:<id>after the infrastructure was applied.tests/cli/test_apply_reports_to_command_center.pypins the new event.Before and after, on the OpenTofu engine with
--build-id no_such_build(the contract's build ismake_rows):Not changed here, on purpose:
--build-idon a contract with no builds still exits 0, as the runner does.suggest_on_error, default on from 3.15), but none of the three other unknown-value errors (expose_not_found,rollback_snapshot_name_not_found,provider_unknown) has it. It belongs in one shared helper for all four.Type of Change
Documentation
docs/cli/apply.md: the--build-idmatch in the "Build ids" subsection, with the real output; a sentence on the--build-idflag row; and an errors-table row.docs/upgrading.md.docs/advanced/production-troubleshooting.md, the page the CLI's docs link for this event opens.docs/advanced/operating-in-ci.md.Checklist
pytest)ruff checkandblackwith no errorspython scripts/add_license_headers.py;examples/**exempt)Testing
tests/cli/test_apply_build_ids_before_tofu.py, on fix(apply): refuse an unusable build id before tofu apply #803's harness:tofuand the apply hooks are recorders, and the real build runner runs behind a spy. On main 8755906, 21 of them fail and 11 pass (the 11 are controls), and the updated Command Center pin fails. All pass on the branch.amend-and-buildandreplace-and-build, near misses (a typo, wrong case, a trailing space, a prefix), builds without an id, the order against the id-grammar gate, the CLI rendering throughmain(), and the runner backstop on the same near misses.tofuand then the runner with that id, an empty--build-idfilters nothing, and a contract without builds is not refused.fluidCLI from a scratch directory, with a recording stand-intofufirst onPATH(shadowing a real OpenTofu 1.13.1) and no credentials. 27 of 27 checks pass:fluid validateaccepts,--build-id make_row: refused withERR_APPLY_BUILD_ID_NOT_FOUND, 0 tofu calls and no.fluid/iacdirectory. The same holds with--dry-run, withreplace-and-build --allow-data-loss, and for aplan.jsonwritten by the realfluid plan.--build-id make_rowsthe apply reachestofu(control).tofuand creates.fluid/iac, and the native one fails untyped.python:3.12-slimcontainer on the changed files: rc 0, baseline unchanged.ruff --select F401,F841on the changed files gives the same 17 hits as main.tests/perf/test_startup_budget.pyhas the same module counts on main 26f1875 and on the branch (1031 and 1933). Its module-count failures in this venv predate this change.--env, plan.json,.tgzbundle), the order against the plan-binding, data-loss, schema and id-grammar gates, every producer of--build-id(schedulers, CI templates,generate ci), ids made of escape sequences, Rich markup and secret shapes, and what the logs and Command Center record.Found along the way, not in this PR: the Dagster and Prefect emitters in
cli/_acquisition_stage_ext.py(lines 623 and 644) still generate the retiredfluid apply --build <id>.